package com.nakamachizu.controller;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.slim3.controller.Controller;
import org.slim3.controller.Navigation;
import org.slim3.controller.validator.Validators;
import org.slim3.util.StringUtil;
import org.slim3.util.TimeZoneLocator;

import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.nakamachizu.collection.MailData;
import com.nakamachizu.constant.AppConstant;
import com.nakamachizu.model.MapData;
import com.nakamachizu.service.MapDataService;
import com.nakamachizu.util.ErrorsUtil;
import com.nakamachizu.util.ForwardUtil;
import com.nakamachizu.util.MailUtil;
import com.nakamachizu.util.TokenCheck;

public class MailController extends Controller {

    private static final Logger log = Logger.getLogger(MailController.class.getName());
    private String key;
    private String cmd_send;
    private String cmd_confirm;
    private String to;
    private String from;
    private String subject;
    private String body;
    private String toAddressCsv;
    private List<String>toAddressList;
    private String title;
    private String isViewPassword;
    private String name;
    
    @Override
    public Navigation run() {
        
        UserService userService = UserServiceFactory.getUserService();
        User user = userService.getCurrentUser();

        init();
        
        MapDataService mds = new MapDataService();
        MapData map = mds.getMapDataAccessKey(key);
        
        if(AppConstant.FROM_MAIL_ADDRESS_SYSTEM().equals(map.getFromMailAddress())){
            from = AppConstant.WELCOME_MAIL_ADDRESS();
        }else{
            from = user.getEmail();
        }
        requestScope("from", from);
        
        if(!validate()){
            return forward(ForwardUtil.forwardJsp("mail.jsp"));
        }
        
        if(!StringUtil.isEmpty(cmd_send)){
            if(!TokenCheck.validate(request)){
                ErrorsUtil.putErrors(errors, request, "message.error.token", "token_error");
                return forward(ForwardUtil.forwardJsp("mail.jsp"));
            }

            if(map.getAdminMailAddress().equals(user.getEmail())){
                try{
                    MailUtil mu = new MailUtil();
                    List<String>toList = new ArrayList<String>();
                    if(!StringUtil.isEmpty(to)){
                        toList.add(to);
                    }
                    if(toAddressList != null && toAddressList.size() > 0){
                        toList.addAll(toAddressList);
                    }
                    toList = this.margeAddress(toList);
                    mu.send(toList, from, subject, this.makeBody(map), null);
                    return forward(ForwardUtil.forwardJsp("mail_send.jsp"));
                }catch(IOException e){
                    ErrorsUtil.stackTrace(e);
                    ErrorsUtil.putErrors(errors, request, "message.error.sendfailed", "send_exception");
                }
            }
        }
        
        if(!StringUtil.isEmpty(cmd_confirm)){
            TokenCheck.saveToken(request);
            requestScope("mailbody", this.makeBody(map));
            return forward(ForwardUtil.forwardJsp("mail_confirm.jsp"));
        }
        
        return forward(ForwardUtil.forwardJsp("mail.jsp"));
    }
    
    protected boolean validate() {
        boolean result = false;
        Validators v = new Validators(request);
        v.add("key", v.required());
        if(!StringUtil.isEmpty(cmd_send) || !StringUtil.isEmpty(cmd_confirm)){
            v.add("subject", v.required());
            v.add("body", v.required());
            v.add("name", v.required());
            if(toAddressList == null){
                v.add("to", v.required());
            }
            if(!StringUtil.isEmpty(to)){
                if(!MailUtil.isValidMailAddress(to)){
                    ErrorsUtil.putErrors(errors, request, "message.error.mailaddress", "to", to);
                }
            }
        }

        result = v.validate();
        
        return result;
    }
    
    protected void init(){
        key = requestScope("key");
        cmd_send = requestScope("cmd_send");
        cmd_confirm = requestScope("cmd_confirm");
        to = requestScope("to");
        subject = requestScope("subject");
        body = requestScope("body");
        toAddressCsv = requestScope("toAddressCsv");
        name = requestScope("name");
        if(!StringUtil.isEmpty(toAddressCsv)){
            for(String str : toAddressCsv.split(",")){
                if(MailUtil.isValidMailAddress(str)){
                    if(toAddressList == null){
                        toAddressList = new ArrayList<String>();
                    }
                    toAddressList.add(str);
                }
            }
            requestScope("toAddressList", toAddressList);
        }
    }
    
    @Override
    protected Navigation handleError(Throwable error) {
        error.printStackTrace();
        log.severe(ErrorsUtil.stackTrace(error));
        return forward("error.jsp");
    }
    
    protected String makeBody(MapData map){
        
        String result = null;
        try{
            MailData mail = new MailData();
            mail.setName(name);
            mail.setBody(body);
            mail.setFrom(from);
            mail.setServerName(request.getServerName());
            mail.setKey(key);
            mail.setTitle(map.getTitle());
            if(!StringUtil.isEmpty(map.getViewPassword())){
                mail.setViewPassword(map.getViewPassword());
            }
            mail.setAccessLevel(map.getAccessLevel());
            if(map.getExpire() != null){
                Calendar cal = Calendar.getInstance(TimeZoneLocator.get());
                cal.setTime(map.getExpire());
                StringBuffer buf = new StringBuffer();
                buf.append(cal.get(Calendar.YEAR ))
                .append("/")
                .append(cal.get(Calendar.MONTH) + 1)
                .append("/")
                .append(cal.get(Calendar.DAY_OF_MONTH))
                .append(" ")
                .append(cal.get(Calendar.HOUR_OF_DAY))
                .append(":")
                .append(cal.get(Calendar.MINUTE))
                .append(":")
                .append(cal.get(Calendar.SECOND));
                mail.setExpire(buf.toString());
            }
            
            Velocity.init("WEB-INF/velocity_conf.properties");
            VelocityContext context = new VelocityContext();

            context.put("mail", mail);

            StringWriter sw = new StringWriter();
            Template template = Velocity.getTemplate("mail.tmpl", "UTF-8");
            template.merge(context, sw);
            result = sw.toString();
            sw.flush();
            
        }catch(Exception e){
            log.severe(ErrorsUtil.stackTrace(e));
        }
        
        return result;
    }
    
    protected List<String>margeAddress(List<String> list){
        List<String>result = null;
        if(list != null){
            Map<String, String>map = new LinkedHashMap<String, String>();
            result = new ArrayList<String>();
            for(String str : list){
                map.put(str, "1");
            }
            for(String str : map.keySet()){
                result.add(str);
            }
            
        }
        return result;
    }
}
